<?php
/** Copyright 2014 TinPhp Systems, Inc.
 * @author zhangxilian 2013-1-20
 * @package TinPhp
 */

/**
 * 底层数据操作基类，只能继承，并实现对应的虚拟方法
 */
abstract class TinDaoBase {
	protected $table;
	protected $db;
	protected $view;
	protected $logger;
	protected $tableSeq;
	protected $tableId;
	protected $seqOff;
	/** 根据指定参数，分页查询数据记录
     * @param string $cols 数据表字段名称 col1,col2,col3...
     * @param string $cond 查询条件(字段1=条件1 and 字段2=条件2)
     * @param int $page 当前要查询页数，默认1
     * @param int $size 每页显示数，默认10
     * @param bool $params 可以执行绑定变量使用 array类型
     * @param string $extra 语句的最后附加条件
     * @return Array
     *  */
	abstract protected function selectByCond($cols, $cond, $page = 1, $size = 10, $params = false, $extra = null);
    /** 根据指定参数，插入数据记录
     * @param TinDataMap $zxData 数据对象 @see TinDataMap
     * @param bool $checkDataType 是否检测数据类型，默认true
     * @param bool $tick 是否返回最后的ID值，默认true
     * @param bool $params 可以执行绑定变量使用 array类型
     * @return int
     *  */
	abstract protected function insert(& $zxData, $checkDataType = true, $tick = true, $params=false);
    /** 获取最后的一条更新记录的ID
     * @param string $table_name_seq 序列名称，仅Oracle有用
     * @return int
     *  */
	abstract protected function getLastInsertId($table_name_seq = null);
     /** 根据指定ID，更新数据记录
     * @param TinDataMap $zxData 数据对象 @see TinDataMap
     * @param int $id 指定数据ID
     * @param bool $checkDataType 是否检测数据类型，默认true
     * @return int
     *  */
	abstract protected function updateByID(& $zxData, $id, $checkDataType = true);
    /** 根据指定条件，更新数据记录
     * @param TinDataMap $zxData 数据对象 @see TinDataMap
     * @param string $cond 查询条件(字段1=条件1 and 字段2=条件2)
     * @param bool $checkDataType 是否检测数据类型，默认true
     * @param bool $params 可以执行绑定变量使用 array类型
     * @param string $extra 语句的最后附加条件
     * @return int
     *  */
	abstract protected function updateByCond(& $zxData, $cond, $checkDataType = true, $params = false, $extra = null);
    /** 根据指定条件，删除数据记录
     * @param string $cond 查询条件(字段1=条件1 and 字段2=条件2)
     * @param bool $params 可以执行绑定变量使用 array类型
     * @param string $extra 语句的最后附加条件
     * @return int
     *  */
	abstract protected function deleteByCond($cond, $params = false, $extra = null);
	
	/** 删除指定ID值记录
	 * @param int $id 指定ID值,列名由view对象中设置
	 * */
	public function deleteById($id) {
		return $this->deleteByCond($this->view->getId()."=:pkid", array("pkid"=>$id));
	}
	
	/** 直接执行一句SQL，请慎用
	 * @param string $sqlStr 要执行的SQL语句
	 * @param array $params 支持绑定变量Array
	 * */
	public function executeSQL($sqlStr, $params=false){
        try{
            $this->logger->info("executeSQL:".$sqlStr."   ".(is_array($params) ? "params:".implode('_',$params) :""));
            return $this->db->Execute($sqlStr, $params);
        }catch(Exception $e){
			$this->logger->error("executeSQL".$sqlStr."\n ERROR:".$e->getMessage());
			throw new DBException("executeSQL Fail: ".$e->getMessage());
		}
	}
	
	/** Select执行一句SQL
	 * @param string $sqlStr 要执行的SQL语句
	 * @param array $params 支持绑定变量Array
	 *  */
	public function getAllForSql($sqlStr, $params=false){
        try{
            $this->logger->info("executeSQL:".$sqlStr."   ".(is_array($params) ? "params:".implode('_',$params) :""));
            return $this->db->GetAll($sqlStr, $params);
        }catch(Exception $e){
			$this->logger->error("getAllForSql:".$sql."\n ERROR:".$e->getMessage());
			throw new DBException("getAllForSql Fail: ".$e->getMessage());
		}
	}
	
	/** UnionAll应用，自己组SQL进来
     * @param string $unionSQLS 组好Union的SQL串
     * @param int $page 当前页数,默认不分页
     * @param int $size 每页显示数
	 * */
	public function selectByCondUnionAll($unionSQLS, $page=null, $size=null){
		if(""==$unionSQLS || null==$unionSQLS){
			throw new DBException("selectByCondUnionAll Fail: unionSQLS is null ");
		}
		$unionNum = count($unionSQLS);
		$sqlUnion = "";
		for($i=0; $i<$unionNum; $i++){
			if($i > 0) {
				$sqlUnion .= " union all ";
			}
			$sqlUnion .= " ".$unionSQLS[$i]." ";
		}
		
		if(TIN_DB_TYPE=="oci8"){
			$sqlTable = "select zxtable.*, ROWNUM rn from ($sqlUnion) zxtable ";
			if($page && $size){		
				$sql .= "select * from (" . $sqlTable . " where ROWNUM <=". ($page*$size)." order by grade asc, x";
				$sql .= ") where rn > ". (($page-1)*$size) ." order by grade asc, x";
				$sqlTable = $sql;
			}
		}else{
			$sqlTable = "select * from ($sqlUnion) zxtable ";
			if($page && $size){
				$sqlTable .= " limit ".($page-1)*$size.",$size";
			}
		}
		
        try{
            $this->logger->info("selectByCondUnionAll: sqlTable=".$sqlTable."  \n sqlUnion=".$sqlUnion);
            $returnVAL = array();
            $returnVAL["data"] = $this->db->GetAll($sqlTable);
            $returnVAL["count"] = $this->db->GetOne("select count(*) from (".$sqlUnion.")");
            return $returnVAL;
        }catch(Exception $e){
			$this->logger->error("selectByCondUnionAll: sqlTable=".$sqlTable."  \n sqlUnion=".$sqlUnion."\n ERROR:".$e->getMessage());
			throw new DBException("selectByCondUnionAll Fail: ".$e->getMessage());
		}
	}
	
	/**
	 * 查找所有记录，不分页，支持多表查询
	 * @param string $cols 要查找的字段名称,默认所有“*”
	 * @param string $cond 条件
	 * @param string $extra 附加条件，或排序条件" order by id "
	 * @param array $params 可以执行绑定变量使用 array类型
	 * @return array
	 * */
	public function selectAll($cols=null, $cond=null, $extra=null, $params = false) {		
        $colStmt = $this->convColStmt($cols);
        if(""==$colStmt)$colStmt="*";
        $sql = "select " . $colStmt . " from " . $this->table." ".$this->view->getTableLeftJoin();
        $where=" where 1=1 ";
        if ($this->view->isMultiple()) {
            $mulWhere = $this->view->getTableStmtCond();
            $where .= " and " . $mulWhere;
        }
        if ($cond != null) {
            $where .= " and " . $cond;
        }
        $sql .= $where;
        if ($extra != null) {
            $sql .= " " . $extra;
        }
        try{
            $this->logger->info("selectAll:".$sql."   ".(is_array($params) ? "params:".implode('_',$params) :""));
			return $this->db->GetAll($sql, $params);
		}catch(Exception $e){
			$this->logger->error("selectAll:".$sql."\n ERROR:".$e->getMessage());
			throw new DBException("selectAll Fail: ".$e->getMessage());
		}
	}
	
	/**
	 * 根据条件获取指定列的一条记录
	 * @param string $cols 要查找的字段名称,默认所有“*”
	 * @param string $cond 指定查询条件
	 * @param array $params 可以执行绑定变量使用 array类型
     * @return array
	 * */
	public function selectRowByCond($cols, $cond, $params = false) {		
        $colStmt = $this->convColStmt($cols);
        $sql = "select " . $colStmt . " from " . $this->table." ".$this->view->getTableLeftJoin();

        $condStmt = "";
        if ($this->view->isMultiple()) {
            $conj = $this->view->getTableStmtCond();
            $condStmt = $conj . " AND (" . $cond . ")";
        } else {
            $condStmt .= $cond;
        }
        $sql .= " where ".$condStmt;
        try{
            $this->logger->info("selectRowByCond:".$sql."   ".(is_array($params) ? "params:".implode('_',$params) :""));
			return $this->db->GetRow($sql,$params);
		}catch(Exception $e){
			$this->logger->error("selectRowByCond:".$sql."\n ERROR:".$e->getMessage());
			throw new DBException("selectRowByCond Fail: ".$e->getMessage());
		}
	}
	/**
	 * 根据条件统计记录数
	 * @param string $cond 要统计的条件
	 * @param string $subject 用于distinct字段名
	 * @param string $extra 附加条件，或排序
	 * @param array $params 可以执行绑定变量使用 array类型
	 * @return int
	 * */
	public function getCountByCond($cond, $subject = null, $extra = null, $params = false) {
        $sql = "";
		try{
			if ($subject != null) {
				$sql = "select count(distinct " . $subject . ") from " . $this->table;
			} else {
				$sql = "select count(*) from " . $this->table;
			}
	
			$condStmt = "";
			if ($this->view->isMultiple()) {
				$conj = $this->view->getTableStmtCond();
				$condStmt = $conj . " AND (" . $cond . ")";
			} else {
				$condStmt .= $cond;
			}
			if($condStmt!=""){
				$sql = $sql . " where " . $condStmt;
			}
			if ($extra != null) {
				$sql .= " " . $extra;
			}
            $this->logger->info("getCountByCond:".$sql."   ".(is_array($params) ? "params:".implode('_',$params) :""));
			return $this->db->GetOne($sql, $params);
		}catch(Exception $e){
			$this->logger->error("getCountByCond:".$sql."\n ERROR:".$e->getMessage());
			throw new DBException("getCountByCond Fail: ".$e->getMessage());
		}
	}
	
	
	//===========================================================================================
	/** 开启数据库事务 */
	protected function beginTrans() {
		$this->db->StartTrans();
	}
    /** 结束并提交数据库事务 */
	protected function endTrans() {
		$this->db->CompleteTrans();
	}
    /** 回滚数据库事务 */
	protected function rollBack() {
		$this->db->rollback();
	}
	
	/** 废弃的方法，移交Adodb5来验证，用于判断是否在SQL值加入单引号
     * @param DB枚举 $type */
	protected function needAppendQuote($type) {
		switch ($type) {
			case DB::CHAR :
			case DB::VARCHAR :
			case DB::TEXT :
			case DB::ENUM :
				return true;
			default :
				return false;
		}
	}
    /** 如果是字符类型，验证加入单引号
     * @param string $str 值 */
	protected function filterStr($str) {
		$qstr = $this->db->qstr($str);
		return $qstr;
	}
    /** 获取View类定义的所有字段，如果用的AssignTable通用类无返回 */
	protected function getAllColStmt() {
		$cols = $this->view->getNames();
		return $this->convColStmt($cols);
	}
    /** 组织字段名称 */
	protected function convColStmt($cols) {
		$colStmt = "";
		if (!is_array($cols)){ //判断是否是数组
			$cols = explode(",", $cols);
		}		
		$colsNum = count($cols);
		for ($i = 0; $i < $colsNum; $i++) {
			$colStmt .= $cols[$i];
			if ($i < $colsNum -1)
				$colStmt .= ",";
		}
		$colStmt = TIN_DB_FIELD_UPPER ? strtoupper($colStmt) : strtolower($colStmt);
		return $colStmt;
	}
	//===========================================================================================
	
}//End Class
?>